package com.easylinkin.linkappapi.concretestrength.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import com.aliyuncs.utils.StringUtils;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.easylinkin.linkappapi.common.model.RequestModel;
import com.easylinkin.linkappapi.common.service.CommonService;
import com.easylinkin.linkappapi.common.utils.excel.ExcelConstant;
import com.easylinkin.linkappapi.common.utils.excel.ExcelTools;
import com.easylinkin.linkappapi.common.utils.io.OutputStreamUtil;
import com.easylinkin.linkappapi.concretestrength.dto.ConcreteStrengthDetailDTO;
import com.easylinkin.linkappapi.concretestrength.dto.ConcreteStrengthInfoDTO;
import com.easylinkin.linkappapi.concretestrength.entity.ConcreteStrengthDetail;
import com.easylinkin.linkappapi.concretestrength.entity.ConcreteStrengthInfo;
import com.easylinkin.linkappapi.concretestrength.entity.ConcreteStrengthRecord;
import com.easylinkin.linkappapi.concretestrength.entity.vo.*;
import com.easylinkin.linkappapi.concretestrength.mapper.ConcreteStrengthDetailMapper;
import com.easylinkin.linkappapi.concretestrength.mapper.ConcreteStrengthInfoMapper;
import com.easylinkin.linkappapi.concretestrength.mapper.ConcreteStrengthRecordMapper;
import com.easylinkin.linkappapi.concretestrength.service.ConcreteStrengthInfoService;
import com.easylinkin.linkappapi.security.context.LinkappUserContextProducer;
import com.easylinkin.linkappapi.security.entity.LinkappUser;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import site.morn.rest.RestBuilders;
import site.morn.rest.RestMessage;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;
import java.io.Serializable;
import java.util.*;

/**
 * ConcreteStrengthInfo表服务实现类
 *
 * @author zhengwen
 * @date 2022/10/23
 */
@Slf4j
@Service("appConcreteStrengthInfoService")
public class ConcreteStrengthInfoServiceImpl extends ServiceImpl<ConcreteStrengthInfoMapper, ConcreteStrengthInfo> implements ConcreteStrengthInfoService {
    @Resource
    private CommonService commonService;
    @Resource
    private LinkappUserContextProducer linkappUserContextProducer;

    @Resource
    private ConcreteStrengthDetailMapper concreteStrengthDetailMapper;

    @Resource
    private ConcreteStrengthRecordMapper concreteStrengthRecordMapper;

    @Override
    public boolean saveOne(ConcreteStrengthInfo appConcreteStrengthInfo) {
        commonService.setCreateAndModifyInfo(appConcreteStrengthInfo);
        // appConcreteStrengthInfo.setTenantId(linkappUserContextProducer.getNotNullCurrent().getTenantId());
        validParamRequired(appConcreteStrengthInfo);
        validRepeat(appConcreteStrengthInfo);
        validParamFormat(appConcreteStrengthInfo);
        return save(appConcreteStrengthInfo);
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateOne(ConcreteStrengthInfo appConcreteStrengthInfo) {
        Assert.notNull(appConcreteStrengthInfo.getId(), "id不能为空");
        commonService.setModifyInfo(appConcreteStrengthInfo);
        //appConcreteStrengthInfo.setTenantId(linkappUserContextProducer.getNotNullCurrent().getTenantId());
        validRepeat(appConcreteStrengthInfo);
        validParamFormat(appConcreteStrengthInfo);
        return updateById(appConcreteStrengthInfo);
    }

    @Override
    public IPage<ConcreteStrengthInfo> selectPage(Page page, ConcreteStrengthInfo appConcreteStrengthInfo) {
        //appConcreteStrengthInfo.setTenantId(linkappUserContextProducer.getNotNullCurrent().getTenantId());
        return baseMapper.selectPage(page, appConcreteStrengthInfo);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean deleteByIds(List<Long> idList) {
        return removeByIds(idList);
    }

    @Override
    public void export(ConcreteStrengthInfo appConcreteStrengthInfo, HttpServletRequest request, HttpServletResponse response) {

        IPage<ConcreteStrengthInfo> page = selectPage(new Page(0, -1), appConcreteStrengthInfo);
        List<ConcreteStrengthInfo> records = page.getRecords();
        List<ConcreteStrengthInfoVo> appConcreteStrengthInfoVos = new ArrayList<>();
        for (ConcreteStrengthInfo expert : records) {
            appConcreteStrengthInfoVos.add(new ConcreteStrengthInfoVo(expert));
        }

        String keyValue = "名称:name,租户id:tenantId";
        String title = "ConcreteStrengthInfo导出数据";
        String fileName = title + ".xls";
        try {
            OutputStream outputStream = OutputStreamUtil.getOutputStream(request, response, fileName);
            ExcelTools.exportExcel(outputStream, keyValue, appConcreteStrengthInfoVos, ExcelConstant.XLS, title);
            response.flushBuffer();
            outputStream.close();
        } catch (IOException e) {
            log.error("excel导出失败", e);
            throw new RuntimeException("excel导出失败！IOException异常" + e.getMessage());
        } catch (Exception e) {
            log.error("excel导出失败", e);
            throw new RuntimeException("excel导出失败！" + e.getMessage());
        }
    }

    @Override
    public RestMessage saveCheckData(ConcreteStrengthVo concreteStrengthVo) {
        LinkappUser linkappUser = linkappUserContextProducer.getNotNullCurrent();
        String tenantId = linkappUser.getTenantId();
        //参数校验
        checkConcreteData(concreteStrengthVo);

        List<ConcreteStrengthInfoVo> infoVoList = concreteStrengthVo.getInfoVoList();
        //执行保存数据
        Date now = DateUtil.date();
        for (ConcreteStrengthInfoVo vo : infoVoList) {
            //先存info
            ConcreteStrengthInfo info = new ConcreteStrengthInfo();
            BeanUtil.copyProperties(vo, info, CopyOptions.create().setIgnoreNullValue(true));
            info.setTenantId(tenantId);
            info.setDeleteState(1);
            info.setCreateTime(now);
            info.setCreator(linkappUser.getId().toString());
            info.setModifier(info.getCreator());
            info.setModifyTime(info.getCreateTime());
            baseMapper.insert(info);

            Long infoId = info.getId();
            List<ConcreteStrengthDetailVo> detailVoLs = vo.getDetailList();
            if (CollectionUtil.isNotEmpty(detailVoLs)) {
                for (ConcreteStrengthDetailVo detailVo : detailVoLs) {
                    //再存detail
                    ConcreteStrengthDetail detail = new ConcreteStrengthDetail();
                    BeanUtil.copyProperties(detailVo, detail, CopyOptions.create().setIgnoreNullValue(Boolean.TRUE));
                    detail.setInfoId(infoId);
                    detail.setDeleteState(1);
                    detail.setCreator(info.getCreator());
                    detail.setCreateTime(now);
                    detail.setModifier(info.getModifier());
                    detail.setModifyTime(now);
                    concreteStrengthDetailMapper.insert(detail);

                    Long detailId = detail.getId();
                    List<ConcreteStrengthRecord> recordLs = detailVo.getRecordList();
                    if (CollectionUtil.isNotEmpty(recordLs)) {
                        //最后存record
                        for (ConcreteStrengthRecord record : recordLs) {
                            record.setDeleteState(1);
                            record.setCreateTime(now);
                            record.setCreator(info.getCreator());
                            record.setModifier(info.getModifier());
                            record.setModifyTime(now);
                            record.setInfoId(infoId);
                            record.setDetailId(detailId);
                            concreteStrengthRecordMapper.insert(record);
                        }
                    }
                }
            }
        }

        return RestBuilders.successBuilder().build();
    }

    @Override
    public RestMessage selectInfoDtoPage(RequestModel<ConcreteStrengthInfoVo> requestModel) {
        LinkappUser linkappUser = linkappUserContextProducer.getNotNullCurrent();
        String tenantId = linkappUser.getTenantId();
        ConcreteStrengthInfoVo vo = requestModel.getCustomQueryParams();
        vo.setTenantId(tenantId);
        Date startTime = vo.getStartTime();
        Date endTime = vo.getEndTime();
        Date now = DateUtil.date();
        if(StringUtils.isEmpty(vo.getCreateTimeStr()) && endTime == null){
            endTime = DateUtil.endOfDay(now);
        }
        if (startTime == null && endTime == null) {
            startTime = DateUtil.offsetMonth(now, -1);
            endTime = now;
        }
        if(startTime != null){
            startTime = DateUtil.beginOfDay(startTime);
        }
        endTime = DateUtil.endOfDay(endTime);
        vo.setStartTime(startTime);
        vo.setEndTime(endTime);

        Page page = requestModel.getPage();
        IPage<ConcreteStrengthInfoDTO> dtoPage = baseMapper.selectInfoDtoList(page, vo);

        return RestBuilders.successBuilder().data(dtoPage).build();
    }

    @Override
    public RestMessage infoDto(Serializable id) {
        cn.hutool.core.lang.Assert.isTrue(id != null, "ID为空");

        ConcreteStrengthInfoDetailVo infoDetailVo = getOneDtoById(id);

        return RestBuilders.successBuilder().data(infoDetailVo).build();
    }

    @Override
    public RestMessage infoTypeDto(Serializable id) {
        cn.hutool.core.lang.Assert.isTrue(id != null, "ID为空");

        ConcreteStrengthInfoDetailRecordVo vo = new ConcreteStrengthInfoDetailRecordVo();

        ConcreteStrengthInfoDTO dto = baseMapper.selectInfoDto(id);
        if (dto != null) {
            ConcreteStrengthInfo info = new ConcreteStrengthInfo();
            BeanUtil.copyProperties(dto, info, CopyOptions.create().setIgnoreNullValue(true));
            vo.setConcreteStrengthInfo(info);
            vo.setPosition(dto.getPosition());
            vo.setCheckUser(dto.getCheckUser());
            //查询测区信息，detail
            ConcreteStrengthDetail detailExp = new ConcreteStrengthDetail();
            detailExp.setInfoId(dto.getId());
            List<ConcreteStrengthDetailDTO> detailList = concreteStrengthDetailMapper.selectDtoListByDetail(detailExp);
            //处理测区、数据
            if (CollectionUtil.isNotEmpty(detailList)) {
                Map<Integer, Map<String, List<ConcreteStrengthRecord>>> areaRecordMp = new HashMap<>();

                final ConcreteStrengthDetail[] detail = {null};
                detailList.stream().forEach(d -> {
                    if (detail[0] == null) {
                        detail[0] = new ConcreteStrengthDetail();
                        BeanUtil.copyProperties(d, detail[0], CopyOptions.create().setIgnoreNullValue(true));
                        vo.setDetail(detail[0]);
                    }

                    List<ConcreteStrengthRecord> recordList = d.getRecordList();
                    String checkArea = d.getCheckArea();
                    Integer dataType = d.getDataType();
                    if (dataType != null) {
                        Map<String, List<ConcreteStrengthRecord>> mp = areaRecordMp.get(dataType);
                        if (StringUtils.isNotEmpty(checkArea)) {
                            if (CollectionUtil.isEmpty(mp)) {
                                mp = new HashMap<>();
                            }
                            mp.put(checkArea, recordList);
                        }
                        areaRecordMp.put(dataType, mp);
                    }
                });
                vo.setAreaRecordMp(areaRecordMp);

            }
        }
        return RestBuilders.successBuilder().data(vo).build();
    }

    @Override
    public ConcreteStrengthInfoDetailVo getOneDtoById(Serializable id) {
        ConcreteStrengthInfoDetailVo infoDetailVo = new ConcreteStrengthInfoDetailVo();

        ConcreteStrengthInfoDTO dto = baseMapper.selectInfoDto(id);
        if (dto != null) {
            BeanUtil.copyProperties(dto, infoDetailVo, CopyOptions.create().setIgnoreNullValue(true));

            infoDetailVo.setPosition(dto.getPosition());
            infoDetailVo.setCheckUser(dto.getCheckUser());

            //查询测区信息，detail
            ConcreteStrengthDetail detailExp = new ConcreteStrengthDetail();
            detailExp.setInfoId(dto.getId());
            List<ConcreteStrengthDetailDTO> detailList = concreteStrengthDetailMapper.selectDtoListByDetail(detailExp);
            //处理测区、数据
            if (CollectionUtil.isNotEmpty(detailList)) {
                Map<String, Map<Integer, List<ConcreteStrengthDetailDTO>>> areaMp = new HashMap<>();
                detailList.stream().forEach(d -> {
                    String checkArea = d.getCheckArea();
                    Map<Integer, List<ConcreteStrengthDetailDTO>> detailMp = areaMp.get(checkArea);
                    if (CollectionUtil.isEmpty(detailMp)) {
                        detailMp = new HashMap<>();
                    }
                    Integer dataType = d.getDataType();
                    List<ConcreteStrengthDetailDTO> dLs = detailMp.get(dataType);
                    if (CollectionUtil.isEmpty(dLs)) {
                        dLs = new ArrayList<>();
                    }
                    dLs.add(d);

                    detailMp.put(dataType, dLs);

                    areaMp.put(checkArea, detailMp);

                });
                //设置测区测试数据
                infoDetailVo.setAreaMp(areaMp);
            }
        }
        return infoDetailVo;
    }

    /**
     * 检验检测数据
     *
     * @param concreteStrengthVo
     */
    private void checkConcreteData(ConcreteStrengthVo concreteStrengthVo) {
        boolean dataOk = true;
        List<ConcreteStrengthInfoVo> infoVoList = concreteStrengthVo.getInfoVoList();
        if (CollectionUtil.isEmpty(infoVoList)) {
            dataOk = false;
        }
        cn.hutool.core.lang.Assert.isTrue(dataOk, "检测数据为空");
        for (ConcreteStrengthInfoVo vo : infoVoList) {
            List<ConcreteStrengthDetailVo> detailVoLs = vo.getDetailList();
            if (CollectionUtil.isEmpty(detailVoLs)) {
                dataOk = false;
                break;
            }
            for (ConcreteStrengthDetailVo detailVo : detailVoLs) {
                List<ConcreteStrengthRecord> recordLs = detailVo.getRecordList();
                if (CollectionUtil.isEmpty(recordLs)) {
                    dataOk = false;
                    break;
                }
            }
        }
        cn.hutool.core.lang.Assert.isTrue(dataOk, "检测数据异常");
    }

    @Override
    public ConcreteStrengthInfo getOneById(Serializable id) {
        return baseMapper.getOneById(id);
    }

    /**
     * 校验重复
     */
    private void validRepeat(ConcreteStrengthInfo appConcreteStrengthInfo) {
        /* QueryWrapper<ConcreteStrengthInfo> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("name", appConcreteStrengthInfo.getName());
        queryWrapper.eq("tenant_id", linkappUserContextProducer.getNotNullCurrent().getTenantId());
        List<ConcreteStrengthInfo> list = baseMapper.selectList(queryWrapper);
        if (list.size() == 0) {
            return;
        }
        if (list.size() > 1) {
            throw new BusinessException("名称有重复");
        }
        if (ObjectUtils.isEmpty(appConcreteStrengthInfo.getId())) {
            throw new BusinessException("名称已存在");
        }
        if (!appConcreteStrengthInfo.getId().equals(list.get(0).getId())) {
            throw new BusinessException("名称已存在");
        }
                    */

    }


    /**
     * 校验参数必填
     */
    private void validParamRequired(ConcreteStrengthInfo appConcreteStrengthInfo) {
        //Assert.notNull(appConcreteStrengthInfo, "参数为空");
        //Assert.isTrue(StringUtils.isNotBlank(appConcreteStrengthInfo.getName()), "名称为空");
    }

    /**
     * 校验参数格式
     */
    private void validParamFormat(ConcreteStrengthInfo appConcreteStrengthInfo) {
        //Assert.isTrue(appConcreteStrengthInfo.getName() == null || appConcreteStrengthInfo.getName().length() <= 50,
        //        "名称超长");
    }
}

